package session

import (
	"dmsv/agent"
	"dmsv/call"
	"dmsv/callrouter"
	"dmsv/common"
	"dmsv/ivr"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"time"
)

const (
	call_cmd_satisfaction = "satisfction"
	call_cmd_start_ivr    = "sivr"
	call_cmd_ivr_play     = "ivr"
	call_cmd_play         = "play"
	call_cmd_play_wait    = "wait"
	call_cmd_leave_play   = "leaveplay"
	call_cmd_leave_msg    = "leave"
	call_cmd_play_bridge  = "playbridge"
	call_cmd_bridge       = "bridge"
	call_cmd_connect      = "connect"
	call_cmd_stop         = "stop"
	call_cmd_call_service = "callservice"
	call_cmd_destroy      = "destroy"
)

type cmd_info struct {
	cName string
	data  interface{}
}

func (s *SessionInfo) PlayVoiceToUser(media string) {

	ev := cmd_info{
		cName: call_cmd_play,
		data:  media,
	}

	s.evChan <- ev
}

//停止播放
func (s *SessionInfo) StopPlay(media string) {

	ev := cmd_info{
		cName: call_cmd_stop,
		data:  media,
	}

	s.evChan <- ev
}

//放音完成后挂机
func (s *SessionInfo) HangUpAfterPlay(media string) {

	uCall, ok := s.call[s.uCallId]
	if ok {
		uCall.PlayFileAndHangup(media)
	} else {
		logs.Error("%v 无用户call信息，放音失败", s.sessionId)
	}
}

//启动满意度
func (s *SessionInfo) Satisfaction(media string) {

	args := cmd_info{
		cName: call_cmd_satisfaction,
		data:  media,
	}

	s.evChan <- args
}

type play_bridge_arg struct {
	userMedia    string
	serviceMedia string
}

func (s *SessionInfo) PlayAndBridge(serviceMedia, userMedia string) {

	arg := play_bridge_arg{
		userMedia:    userMedia,
		serviceMedia: serviceMedia,
	}

	args := cmd_info{
		cName: call_cmd_play_bridge,
		data:  arg,
	}

	s.evChan <- args
}

//获取按键
func (s *SessionInfo) CmdUserGetKeys(args DTMF_ARGS) {

	param := call.DTMF_ARGS{
		KeyStop:   args.KeyStop,
		EndKey:    args.EndKey,
		MaxKey:    args.MaxKey,
		TimeOut:   args.TimeOut,
		MediaFile: args.MediaFile,
		PlayTimes: args.PlayTimes,
	}

	uCall := s.call[s.uCallId]
	uCall.CmdGetKeys(param)
}

//桥接通话
func (s *SessionInfo) BridgeUser() {

	cmd := cmd_info{
		cName: call_cmd_connect,
	}

	s.evChan <- cmd
}

//桥接通话
func (s *SessionInfo) BridgeCallUser() {

	cmd := cmd_info{
		cName: call_cmd_bridge,
	}

	s.evChan <- cmd
}

type WaitInfo struct {
	PlayTimes int
	Delay     int
	Media     string
	SecMedia  string
	BLeaveMsg bool
}

//播放等待音
func (s *SessionInfo) PlayWait(args WaitInfo) {

	cmd := cmd_info{
		cName: call_cmd_play_wait,
		data:  args,
	}

	s.evChan <- cmd
}

func (s *SessionInfo) HangUp(reason interface{}) {

	s.Destroy(reason)
}

func (s *SessionInfo) Destroy(reason interface{}) {

	ev := cmd_info{
		cName: call_cmd_destroy,
		data:  reason,
	}

	s.evChan <- ev
}

func (s *SessionInfo) HangUpByApi() {

	ev := cmd_info{
		cName: call_cmd_destroy,
		data:  HANG_UP_API,
	}

	s.evChan <- ev
}

func (s *SessionInfo) dtmfProcess(key string) {

	s.dtmf += key
	switch s.curCmd {
	case call_cmd_satisfaction:
		msg := &CallBackData{
			Event:   CALL_EVENT_SATISFACTION,
			Ssion:   s,
			MsgTime: time.Now(),
		}
		s.CbChan <- msg
		s.satisfaction = key
	default:

		msg := &CallBackData{
			CallId:  s.sessionId,
			Event:   CALL_EVENT_DTMF,
			Ssion:   s,
			MsgTime: time.Now(),
			Data:    s.dtmf,
		}
		s.dtmf = ""
		s.CbChan <- msg
	}
}

func (s *SessionInfo) SetService(serviceId string) {
	s.serviceId = serviceId
}

func (s *SessionInfo) CallService(service *agent.AgentInfo, playWait WaitInfo) {

	s.curCmd = call_cmd_call_service
	//播放等待音
	uCall, ok := s.call[s.uCallId]
	if ok {
		args := call.WaitInfo{
			PlayTimes: playWait.PlayTimes,
			Media:     playWait.Media,
			SecMedia:  playWait.SecMedia,
			BLeaveMsg: playWait.BLeaveMsg,
			Delay:     playWait.Delay,
		}
		uCall.ServiceId = service.ServiceId()
		uCall.PlayWait(args)
	}

	//坐席置忙
	service.SetPhoneBusy()
	s.serviceId = service.ServiceId()

	var serviceCall *call.CallInfo = nil
	var err error
	//发送呼叫通知
	service.WsSendNewCall(s.sessionId, s.caller, s.display, string(s.callType))
	router, local := callrouter.GetRouterByNum(service.GetDsplay(), service.GetServeNumber())
	if local {
		//呼叫本地坐席
		serviceCall, err = call.OutCallService(s.sessionId, s.caller, service.GetServeNumber(), s.evChan)
		if err != nil {
			logs.Error("[%v] 呼叫坐席失败....", s.sessionId)
			s.HangUp(common.ErrSystem)
			return
		}

	} else {
		//呼叫外线
		serviceCall, err = call.OutCallPstn(s.sessionId, s.display, service.GetServeNumber(), router, s.evChan)
		if err != nil {
			logs.Error("[%v] 呼叫坐席失败....", s.sessionId)
			s.HangUp(common.ErrSystem)
			return
		}
	}
	//call 绑定坐席
	serviceCall.SetAgent(service)
	//更新被叫为坐席
	s.callee = service.GetServeNumber()
	//设置坐席callId
	s.sCallId = serviceCall.CallId()
	//会话绑定call
	s.call[serviceCall.CallId()] = serviceCall
}

func (s *SessionInfo) CallServiceWithOutPlay(service *agent.AgentInfo) error {

	s.curCmd = call_cmd_call_service

	//坐席置忙
	service.SetPhoneBusy()
	var serviceCall *call.CallInfo = nil
	var err error
	//发送呼叫通知
	service.WsSendNewCall(s.sessionId, s.caller, s.display, string(s.callType))
	router, local := callrouter.GetRouterByNum(service.GetDsplay(), service.GetServeNumber())
	if local {
		//呼叫本地坐席
		serviceCall, err = call.OutCallService(s.sessionId, s.caller, service.GetServeNumber(), s.evChan)
		if err != nil {
			logs.Error("[%v] 呼叫坐席失败....", s.sessionId)
			s.HangUp(common.ErrSystem)
			return fmt.Errorf("eCall")
		}
	} else {
		//呼叫外线
		serviceCall, err = call.OutCallPstn(s.sessionId, s.display, service.GetServeNumber(), router, s.evChan)
		if err != nil {
			logs.Error("[%v] 呼叫坐席失败....", s.sessionId)
			s.HangUp(common.ErrSystem)
			return fmt.Errorf("eCall")
		}
	}

	//call 绑定坐席
	serviceCall.SetAgent(service)
	//更新被叫为坐席
	s.callee = service.GetServeNumber()
	//设置坐席callId
	s.sCallId = serviceCall.CallId()
	s.serviceId = service.ServiceId()
	logs.Debug("[%v] 设置会话serviceId :%v", s.sessionId, s.serviceId)
	s.call[serviceCall.CallId()] = serviceCall
	return nil
}

func (s *SessionInfo) cmdRun(cmd cmd_info) {

	//状态机条件处理,满意度配置情况下，不再处理其他指令
	if s.curCmd == call_cmd_satisfaction {
		return
	}

	s.curCmd = cmd.cName
	switch cmd.cName {
	case call_cmd_start_ivr:
		sCall, ok := s.call[s.uCallId]
		if ok {
			if ivrhandle, ok := cmd.data.(ivr.Handle); ok {
				sCall.StartIvr(&ivrhandle)
			}

		} else {
			logs.Error("[%v] 查找call 失败。", s.sessionId)
		}

	case call_cmd_satisfaction:
		media := cmd.data.(string)
		s.PlayAndGetKeySimple(1, media)
		s.satisfactionReset()
		//挂断坐席
		sCall, ok := s.call[s.sCallId]
		if ok {
			logs.Debug("[%v] 启动满意度调查,挂断坐席", s.sessionId)
			sCall.ErrHangUp(nil)
		}
	case call_cmd_bridge:

		sCall, ok := s.call[s.sCallId]
		if ok {
			sCall.BridgeCallToUser(s.display, s.callee)
			logs.Debug("[%v] 开始呼叫用户:%v", s.sessionId, s.callee)
		} else {
			logs.Error("[%v] 坐席call信息未找到", s.sessionId)
		}
	case call_cmd_connect:

		uCall, ok := s.call[s.uCallId]
		if ok {
			uCall.ConnectCall(s.sCallId)
			//logs.Debug("[%v] 接通两路通话", s.sessionId)
		} else {
			logs.Error("[%v] 坐席call信息未找到", s.sessionId)
		}
	case call_cmd_play_wait:

		args, ok := cmd.data.(WaitInfo)
		if ok {
			uCall, exist := s.call[s.uCallId]
			if exist {
				param := call.WaitInfo{
					PlayTimes: args.PlayTimes,
					Delay:     args.Delay,
					Media:     args.Media,
					SecMedia:  args.SecMedia,
					BLeaveMsg: args.BLeaveMsg,
				}
				uCall.PlayWait(param)
			} else {
				logs.Error("[%v] 给用户放音失败,call[%v]信息不存在 。", s.sessionId, s.uCallId)
			}
		}

	case call_cmd_play_bridge:

		args, ok := cmd.data.(play_bridge_arg)
		if ok {
			uCall, exist := s.call[s.uCallId]
			if exist {
				uCall.PlayFile(args.userMedia)
			} else {
				logs.Error("[%v] 给用户放音失败,call[%v]信息不存在 。", s.sessionId, s.uCallId)
			}

			if len(args.serviceMedia) > 0 {
				sCall, exist2 := s.call[s.sCallId]
				if exist2 {
					sCall.PlayFile(args.serviceMedia)
				} else {
					logs.Error("[%v] 给坐席放音失败,call[%v]信息不存在 。", s.sessionId, s.sCallId)
				}
			}
		}
	case call_cmd_ivr_play:
		ivrHandle, ok := cmd.data.(ivr.Handle)
		if ok {
			s.cmdRunIvr(ivrHandle)
		} else {
			logs.Error("[%v] 启动ivr 处理失败,参数错误 。", s.sessionId)
		}
	case call_cmd_destroy:

		s.destroyDo(cmd.data)
	}
}

func (s *SessionInfo) eventRun(ev call.CallEvent) {

	msg := &CallBackData{
		CallId:  s.sessionId,
		MsgTime: time.Now(),
		Ssion:   s,
	}
	//方向
	if ev.Call.IsUser() {
		msg.Dir = LEG_DIR_USER
	} else if ev.Call.IsService() {
		msg.Dir = LEG_DIR_SERVICE
	} else {
		msg.Dir = LEG_DIR_THIRD
	}

	logs.Debug("[%v]来自[%v] 的事件:%v.坐席Id:%v,当前指令:%v", s.sessionId, msg.Dir, ev.Name, s.serviceId, s.curCmd)
	switch ev.Name {
	case call.C_EVENT_CREATE:
		logs.Debug("[%v]呼叫channel创建成功", s.sessionId)
		if s.callType == CALL_TYPE_DIRECT {

			logs.Debug("[%v]直拨更新绑定用户侧call信息", s.sessionId)
			s.uCallId = ev.Call.CallId()
			s.call[ev.Call.CallId()] = ev.Call

			msg.Event = CALL_EVENT_START
			s.CbChan <- msg
		}

	case call.C_EVENT_RING:

		msg.Event = CALL_EVENT_RING
		if ev.Call.IsUser() {
			msg.Dir = LEG_DIR_USER
		} else if ev.Call.IsService() {
			msg.Dir = LEG_DIR_SERVICE
		} else if ev.Call.IsPstn() {
			msg.Dir = LEG_DIR_THIRD
		}

		s.CbChan <- msg
	case call.C_EVENT_ANSWER:

		msg.Event = CALL_EVENT_ANSWER
		if s.callType == CALL_TYPE_BACK {
			ev.Call.BridgeCallToUser(s.display, s.callee)
		} else if s.callType == CALL_TYPE_IN {
			if s.curCmd == call_cmd_call_service {

			} else {
				if ev.Call.IsUser() {
					msg.Caller = s.caller
					msg.Callee = s.callee
				}
			}
		} else if s.callType == CALL_TYPE_DIRECT {
			if ev.Call.IsUser() {
				msg.Caller = s.serviceId
				msg.Callee = s.callee
			}
		}

		s.CbChan <- msg

	case call.C_EVENT_PLAYOVER:
		if s.curCmd == call_cmd_play_bridge {
			if ev.Call.IsUser() {
				bCall, ok := s.call[s.sCallId]
				if ok {
					ev.Call.Bridge(bCall)
				} else {
					logs.Error("[%v]桥接用户失败,不存在...")
				}
			}
		} else if s.curCmd == call_cmd_leave_msg {

			time.AfterFunc(2*time.Second, func() {
				logs.Debug("[%v] 留言语音播放完成,会话是否结束:[%v]....", s.sessionId, s.bDestroy)
				if false == s.bDestroy {
					s.leaveMsgTime = time.Now()
				}
			})
			//暂时取消留言时长限制
			//time.AfterFunc(60*time.Second, func() { s.HangUp(common.SuccLeaveMsgOver) })

		} else if s.curCmd == call_cmd_leave_play {
			media, ok := s.curData.(string)
			if ok {
				s.curCmd = call_cmd_leave_msg
				ev.Call.PlayFile(media)
			} else {
				logs.Error("[%v] 放音文件类型错误[%v].挂机", s.sessionId, media)
				ev.Call.ErrHangUp(common.ErrPlayFile)
			}
		}

	case call.C_EVENT_KEY:
		key := ev.Data.(string)
		s.dtmfProcess(key)

	case call.C_EVENT_TIME_OUT:
		s.hangupCall(s.sCallId, common.HANG_UP_TIMEOUT)

	case call.C_EVENT_DESTROY:

		if s.callType == CALL_TYPE_DIRECT {
			//logs.Debug("[%v]直拨更新绑定用户侧call信息", s.sessionId)
			if len(s.uCallId) == 0 {
				s.uCallId = ev.Call.CallId()
				s.call[ev.Call.CallId()] = ev.Call
			}
		}

		if ev.Call.IsUser() {
			s.doDestroy(ev.Call)
		} else {
			s.doCallHangup(ev.Call)
		}

	case call.C_EVENT_CALL_OUT:

		msg.Event = CALL_EVENT_TO_NUMBER
		msg.Data = ev.Data
		s.CbChan <- msg

	case call.C_EVENT_TRANSFER:
		msg.Event = CALL_EVENT_TO_SERVICE
		msg.Data = ev.Data
		s.CbChan <- msg
	case call.C_EVENT_TO_QUEUE:
		msg.Event = CALL_EVENT_ENQUE
		msg.Data = ev.Data
		s.CbChan <- msg

	case call.C_EVENT_LEAVEMSG:
		s.leaveMsgTime = time.Now()
	}
}
func (s *SessionInfo) StartIvr(handle ivr.Handle) {

	ev := cmd_info{
		cName: call_cmd_start_ivr,
		data:  handle,
	}

	s.evChan <- ev

}

func (s *SessionInfo) cmdRunIvr(handle ivr.Handle) {

	s.ivrHandle = handle
	uCall, ok := s.call[s.uCallId]
	if ok {
		uCall.StartIvr(&handle)
	} else {
		logs.Error("[%v] ivr 启动失败,未找到用户会话.", s.sessionId)
	}
}

func (s *SessionInfo) LeaveMessage(media, leavMedia string) {

	s.curCmd = call_cmd_leave_play
	s.curData = leavMedia
	uCall, ok := s.call[s.uCallId]
	if ok {
		uCall.PlayFile(media)
	} else {
		logs.Error("[%v] ivr 启动失败,未找到用户会话.", s.sessionId)
	}
}

func (s *SessionInfo) IsServiceAnswer() bool {

	for _, c := range s.call {
		if false == c.IsUser() {
			//接听时间不为0 则认为是接听
			return c.AnswerTime.IsZero() == false
		}
	}
	return false
}

func (s *SessionInfo) IsUserAnswer() bool {

	for _, c := range s.call {
		if c.IsUser() {
			//接听时间不为0 则认为是接听
			return c.AnswerTime.IsZero() == false
		}
	}
	return false
}
